# # -*- coding: utf-8 -*-
# 1.模型约束描述
# 1)数据加载与预处理：
# 加载CIFAR-10数据集。
# 以下是CIFAR-10数据集中精心重构的4个类别组合，兼顾视觉差异性和分类挑战性：
# 优化后的类别组合：
# 类别2（bird，鸟类）
# 类别3（cat，猫）
# 类别5（dog，狗）
# 类别7（horse，马）
# 筛选策略解析：
# 生物运动特征谱系：
# 飞行生物：2-bird（鸟类）
# 四足哺乳动物：3-cat（猫）、5-dog（狗）、7-horse（马）
# 形态学对比维度：
# 体型梯度：猫（小型）→ 狗（中型）→ 马（大型）
# 运动方式：鸟类（飞行动物）vs 其他（陆地动物）
import matplotlib.pyplot as plt
import numpy as np
from keras.src.datasets.cifar10 import load_data
from keras.src.legacy.preprocessing.image import ImageDataGenerator

(x_train,y_train),(x_test,y_test)=load_data()
train_a=np.where((y_train==2)|(y_train==3)|(y_train==5)|(y_train==7))[0]
test_a=np.where((y_test==2)|(y_test==3)|(y_test==5)|(y_test==7))[0]
# 将训练集和测试集的图像数据归一化到[0, 1]区间，即除以255。
x_train=x_train[train_a]/255
x_test=x_test[test_a]/255
y_train=y_train[train_a]
y_test=y_test[test_a]
dim=len(np.unique(y_train))
from keras.src.utils import to_categorical
y_train=to_categorical(y_train)
y_test=to_categorical(y_test)
# 图像数据增强技术的应用，实现随机翻转、旋转、裁剪等图像数据增强。
idg=ImageDataGenerator(
    horizontal_flip=True,
    shear_range=0.2,
    rotation_range=3
)
# 2)模型结构：
from keras import Model,Sequential,activations,optimizers,layers,losses,metrics
class VGG16(Model):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.con=Sequential([
            layers.Conv2D(16,3,activation=activations.relu),
            layers.Conv2D(16,3,activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(32, 3, activation=activations.relu),
            layers.Conv2D(32, 3, activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(64, 3, activation=activations.relu),
            layers.Conv2D(64, 3, activation=activations.relu),
            layers.Conv2D(64, 3, activation=activations.relu),
            layers.MaxPooling2D(),
            layers.Conv2D(128, 3, activation=activations.relu),
            layers.Conv2D(128, 3, activation=activations.relu),
            layers.Conv2D(128, 3, activation=activations.relu),
            layers.MaxPooling2D()
        ])
        self.fas=layers.Flatten()
        self.den=Sequential([
            layers.Dense(64,activation=activations.relu),
            layers.Dense(64,activation=activations.relu),
            layers.Dense(dim,activation=activations.softmax)
        ])
    def call(self,x,*args, **kwargs):
        x=self.con(x)
        x=self.fas(x)
        x=self.den(x)
        return x

if __name__ == '__main__':
    model=VGG16()
    model.build(x_train.shape)
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc',metrics.Precision,metrics.F1Score,metrics.Recall])
    log=model.fit(idg.flow(x_train,y_train,batch_size=100),epochs=10,validation_data=(x_test,y_test))
    model.summary()
    plt.plot(log.history['acc'],c='r')
    plt.plot(log.history['val_acc'],c='g')
    plt.legend()
    plt.show()
    plt.plot(log.history['loss'], c='r')
    plt.plot(log.history['val_loss'], c='g')
    plt.legend()
    plt.show()
    model.save_weights('model.weights.h5')
    model.load_weights('model.weights.h5')
    model.evaluate(x_test,y_test)
    plt.imshow(x_test[0])
    plt.show()


'''
model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc',metrics.Precision,metrics.F1Score,metrics.Recall])
125/125 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - acc: 0.7118 - f1_score: 0.7085 - loss: 0.7235 - precision: 0.7748 - recall: 0.6294
model.compile(optimizer=optimizers.RMSprop(),loss=losses.categorical_crossentropy,metrics=['acc',metrics.Precision,metrics.F1Score,metrics.Recall])
125/125 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - acc: 0.6815 - f1_score: 0.6763 - loss: 0.7685 - precision: 0.7442 - recall: 0.5879
model.compile(optimizer=optimizers.Adamax(),loss=losses.categorical_crossentropy,metrics=['acc',metrics.Precision,metrics.F1Score,metrics.Recall])
125/125 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - acc: 0.6827 - f1_score: 0.6751 - loss: 0.7862 - precision: 0.7438 - recall: 0.5994
总结 Adam最好
'''
# 3)模型编译：
# 使用优化器。
# 损失函数，适用于多分类问题且标签为整数。
# 评估指标为准确率。
# 4)模型训练：
# 使用训练集数据训练模型，指定训练轮次和批量大小。
# 使用测试集数据进行验证。
# 记录训练过程中的关键指标，评估指标为精度（精确率、召回率、F1）和损失值，以便后续分析和调优。
# 训练过程中，可视化展示训练集、验证集的精度、1oss的变化曲线。
# 简要分析模型的训练效果（分析的内容以注释的形式总结出来）
# 5)性能评估约束：
# 在测试集上使用保存下来的模型文件评估分类模型的性能，包括准确率、混淆矩阵等指标。
# 6)模型优化约束：
# 选择一种优化方法对模型进行进一步优化(如调整学习率、使用正则化、剪枝等），并分析优化后的结果。
# 7)结果可视化：
# 绘制训练和验证过程中的准确率曲线。
# 8)模型保存：
# 将训练好的模型权重保存到文件中。
# 模型调优，考题中要求使用体现不同优化方案的要求，比如超参数方面的，比如说分类精度低的数据集的增强；比如说调整网络结构，比如说调整优化器学习率等；不能只是增加epoch大小，或者调整batch_size就可以，必须采用两种或者两种以上的调优方法进行调优，最终结论要给出综合各种方法调优得出的综合结论